package com.zb.tools;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.nio.charset.Charset;
import java.util.Collection;
import java.util.HashMap;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

public class IniKit
{
    static public class IniFile
    {
    	public long time;
    	HashMap<String,HashMap<String,String>> sectionData=new HashMap<String,HashMap<String,String>>();
    	
    	private ClassLoader getClassLoader() {
    		ClassLoader ret = Thread.currentThread().getContextClassLoader();
    		return ret != null ? ret : getClass().getClassLoader();
    	}
    	
    	private void load(BufferedReader br) throws IOException
    	{
    		String line=br.readLine();
			if(line!=null&&line.length()>0&&line.charAt(0)==0xFEFF)  //Windows text BOM
				line=line.substring(1);
			String section=null;
			while(line!=null)
			{
				line=line.trim();
				int len=line.length();
				if(len>0&&line.charAt(0)!='#') //跳过空行和注释
				{
					if(len>2&&line.charAt(0)=='['&&line.charAt(len-1)==']')  
						section=line.substring(1,len-1).trim(); //得到section名称
					else
					{
						int idx=0;
						while(idx<len&&line.charAt(idx)!='=') idx++;
						if(idx<len)
						{
							HashMap<String,String> data=sectionData.get(section);
							if(data==null)
							{
								data=new HashMap<String,String>();
								sectionData.put(section,data);
							}
							data.put(line.substring(0,idx).trim(),line.substring(idx+1).trim());
						}
					}
				}
				line=br.readLine();
			}
			br.close();
    	}
    	
    	public IniFile(String filename,Charset charset)
    	{
    		try
			{
    			File file=new File(filename);
    			if(file.exists())
    			{
    				time=file.lastModified();
    				FileInputStream stream=new FileInputStream(file);
    	    		load(new BufferedReader(new InputStreamReader(stream,charset)));
    			}
    			else
    			{
    				time=0L;
		    		InputStream stream=getClassLoader().getResourceAsStream(filename);
					load(new BufferedReader(new InputStreamReader(stream,charset)));
    			}
			}
    		catch (IOException e)
			{
				e.printStackTrace();
			}
    	}
    	
    	public IniFile(String data)
    	{
    		try
			{
    			time=0L;
				BufferedReader br=new BufferedReader(new StringReader(data));
	    		load(br);
			}
    		catch (IOException e)
			{
				e.printStackTrace();
			}
    	}
    	
    	public IniFile(File file,Charset charset)
    	{
    		try
			{
    			time=file.lastModified();
    			FileInputStream stream=new FileInputStream(file);
    			BufferedReader br=new BufferedReader(new InputStreamReader(stream,charset));
	    		load(br);
			}
    		catch (FileNotFoundException e)
			{
				e.printStackTrace();
			}
    		catch (IOException e)
			{
				e.printStackTrace();
			}
    	}
    	
    	public boolean containsSection(String section)
    	{
    		return sectionData.containsKey(section);
    	}
    	
    	public boolean containsKey(String section,String key)
    	{
    		HashMap<String,String> data=sectionData.get(section);
    		return data!=null&&data.containsKey(key);
    	}
    	
    	public String get(String section,String key)
    	{
    		return sectionData.get(section).get(key);
    	}
    	
    	public byte getByte(String section,String key)
    	{
    		return Byte.valueOf(sectionData.get(section).get(key));
    	}
    	
    	public boolean getBoolean(String section,String key)
    	{
    		HashMap<String,String> data=sectionData.get(section);
    		if(data!=null)
    		{
    			String ret=data.get(key);
    			if(ret!=null&&(ret.equalsIgnoreCase("true")||ret.equalsIgnoreCase("yes")||ret.equals("1")))
    			   return true;
    		}
    		return false;
    	}
    	
    	public int getInt(String section,String key)
    	{
    		return Integer.valueOf(sectionData.get(section).get(key));
    	}
    	
    	public short getShort(String section,String key)
    	{
    		return Short.valueOf(sectionData.get(section).get(key));
    	}
    	
    	public long getLong(String section,String key)
    	{
    		return Long.valueOf(sectionData.get(section).get(key));
    	}
    	
    	public float getFloat(String section,String key)
    	{
    		return Float.valueOf(sectionData.get(section).get(key));
    	}
    	
    	public double getDouble(String section,String key)
    	{
    		return Double.valueOf(sectionData.get(section).get(key));
    	}
    	
    	
    	public String get(String section,String key,String def)
    	{
    		HashMap<String,String> data=sectionData.get(section);
    		if(data!=null&&data.containsKey(key))
    		   return data.get(key);
    		return def;
    	}
    	
    	public int getByte(String section,String key,byte def)
    	{
    		HashMap<String,String> data=sectionData.get(section);
    		if(data!=null&&data.containsKey(key))
    		{
                return Byte.valueOf(data.get(key));
    		}
    		return def;
    	}
    	
    	public boolean getBoolean(String section,String key,boolean def)
    	{
    		HashMap<String,String> data=sectionData.get(section);
    		if(data!=null)
    		{
    			String ret=data.get(key);
    			if(ret!=null&&(ret.equalsIgnoreCase("true")||ret.equalsIgnoreCase("yes")||ret.equals("1")))
    			   return true;
    		}
    		return def;
    	}
    	
    	public int getInt(String section,String key,int def)
    	{
    		HashMap<String,String> data=sectionData.get(section);
    		if(data!=null&&data.containsKey(key))
    		{
                return Integer.valueOf(data.get(key));
    		}
    		return def;
    	}
    	
    	public short getShort(String section,String key,short def)
    	{
    		HashMap<String,String> data=sectionData.get(section);
    		if(data!=null&&data.containsKey(key))
    		{
                return Short.valueOf(data.get(key));
    		}
    		return def;
    	}
    	
    	public long getLong(String section,String key,long def)
    	{
    		HashMap<String,String> data=sectionData.get(section);
    		if(data!=null&&data.containsKey(key))
    		{
                return Long.valueOf(data.get(key));
    		}
    		return def;
    	}
    	
    	public float getFloat(String section,String key,float def)
    	{
    		HashMap<String,String> data=sectionData.get(section);
    		if(data!=null&&data.containsKey(key))
    		{
                return Float.valueOf(data.get(key));
    		}
    		return def;
    	}
    	
    	public double getDouble(String section,String key,double def)
    	{
    		HashMap<String,String> data=sectionData.get(section);
    		if(data!=null&&data.containsKey(key))
    		{
                return Double.valueOf(data.get(key));
    		}
    		return def;
    	}
    	
    	public Set<String> getSections()
    	{
    		return sectionData.keySet();
    	}
    	
    	public Set<String> getSectionKeys(String section)
    	{
    		HashMap<String,String> data=sectionData.get(section);
    		if(data!=null) return data.keySet();
    		return null;
    	}
    	
    	public Collection<String> getSectionValues(String section)
    	{
    		HashMap<String,String> data=sectionData.get(section);
    		if(data!=null) return data.values();
    		return null;
    	}
    	
    	public HashMap<String,String> getSectionMap(String section)
    	{
    		HashMap<String,String> data=sectionData.get(section);
    		if(data!=null) return data;
    		return null;
    	}
    	
    	public void set(String section,String key,String value)
    	{
    		HashMap<String,String> data=sectionData.get(section);
    		if(data==null) 
    		{
    			data=new HashMap<String,String>();
    			sectionData.put(section,data);
    		}
    		data.put(key,value);
    	}
    	
    	public <T> void set(String section,String key,T value)
    	{
    		HashMap<String,String> data=sectionData.get(section);
    		if(data==null) 
    		{
    			data=new HashMap<String,String>();
    			sectionData.put(section,data);
    		}
    		data.put(key,String.valueOf(value));
    	}
    	
    	public String toString()
    	{
    		StringBuilder sb=new StringBuilder();
    		//首先处理null
    		HashMap<String,String> data=sectionData.get(null);
    		if(data!=null)
    		{
    			for(String key:data.keySet())
    			{
    				if(key!=null) 
    					sb.append(key);
    				sb.append("=");
    				String value=data.get(key);
    				if(value!=null)
    					sb.append(value);
    				sb.append("\r\n");
    			}
    			sb.append("\r\n");
    		}
    		//处理其他非空键值
    		for(String section:sectionData.keySet())
    		if(section!=null)
    		{

    			sb.append('[');
    			if(section!=null)
    				sb.append(section);
    			sb.append("]\r\n");

    			data=sectionData.get(section);
    			for(String key:data.keySet())
    			{
    				if(key!=null) sb.append(key);
    				sb.append("=");
    				String value=data.get(key);
    				if(value!=null)
    					sb.append(value);
    				sb.append("\r\n");
    			}
    			sb.append("\r\n");
    		}
    		return sb.toString();
    	}
    	
    	public void saveFile(String filename,String charset)
    	{
    		StringKit.saveFile(filename,toString(),charset);
    	}
    	
    }
    
    //============================================================================================
    static private ConcurrentHashMap<String,IniFile> cache=new ConcurrentHashMap<String,IniFile>();
    static private IniFile defaultIni;
    
    static public IniFile use()
    {
    	return defaultIni;
    }
    
    static public IniFile use(String filename,Charset charset)
    {
    	IniFile ini=cache.get(filename);
    	if(ini==null)
    	{
    		synchronized (IniKit.class) {
    			ini=cache.get(filename);
    			if(ini==null)
    			{
    				File file=new File(filename);
    				if(file.exists())
    					ini=new IniFile(file,charset);
    				else
    					ini=new IniFile(filename,charset);
		    		cache.put(filename,ini);
		    		if(defaultIni==null) defaultIni=ini;
		    		
    			}
    		}
    	}    	
    	return ini;
    }
    
    static public IniFile set(String filename,String data)
    {
    	IniFile ini=new IniFile(data);
		synchronized (IniKit.class) {
			cache.put(filename,ini);
		}
		return ini;
    }
    
    static public IniFile use(String filename,String charset)
    {
    	return use(filename,Charset.forName(charset));
    }
    
    static public IniFile use(String filename)
    {
    	return use(filename,Charset.defaultCharset());
    }
    
    static public IniFile get(String filename)
    {
    	return cache.get(filename);
    }
    
    static public void del(String filename)
    {
    	cache.remove(filename);
    }
	
}

